#include "stdafx.h"

#ifdef _UNICODE
#	define TRUE_MAP_LIB_DLL_FILE_NAME											_T("TRUEMapLibForWin32U.dll")
#else
#	define TRUE_MAP_LIB_DLL_FILE_NAME											_T("TRUEMapLibForWin32.dll")
#endif // _UNICODE

#define TRUE_MAP_LIB_DECLARE_FUNCTION(function_name)							static FARPROC g_##function_name = NULL
#define TRUE_MAP_LIB_LOAD_FUNCTION(function_name)								((g_##function_name = ::GetProcAddress(g_hDLL, #function_name)) != NULL)
#define TRUE_MAP_LIB_SET_FUNCTION_TO_NULL(function_name)						g_##function_name = NULL

#define TRUE_MAP_LIB_CALL_FUNCTION_1(function_name, arg1)						g_##function_name(arg1)
#define TRUE_MAP_LIB_CALL_FUNCTION_2(function_name, arg1, arg2)					g_##function_name(arg1, arg2)
#define TRUE_MAP_LIB_CALL_FUNCTION_3(function_name, arg1, arg2, arg3)			g_##function_name(arg1, arg2, arg3)
#define TRUE_MAP_LIB_CALL_FUNCTION_4(function_name, arg1, arg2, arg3, arg4)		g_##function_name(arg1, arg2, arg3, arg4)

static HMODULE g_hDLL = NULL;

// functions
TRUE_MAP_LIB_DECLARE_FUNCTION(tmCreate);
TRUE_MAP_LIB_DECLARE_FUNCTION(tmDestroy);
TRUE_MAP_LIB_DECLARE_FUNCTION(tmLoad);
TRUE_MAP_LIB_DECLARE_FUNCTION(tmGetMapHWND);
TRUE_MAP_LIB_DECLARE_FUNCTION(tmSetMapCenterLocationWithZoomLevel);
TRUE_MAP_LIB_DECLARE_FUNCTION(tmSetMapCenterLocation);
TRUE_MAP_LIB_DECLARE_FUNCTION(tmMoveCenterPointWithZoomLevel);
TRUE_MAP_LIB_DECLARE_FUNCTION(tmMoveCenterPoint);
TRUE_MAP_LIB_DECLARE_FUNCTION(tmSetZoomLevel);
TRUE_MAP_LIB_DECLARE_FUNCTION(tmGetZoomLevel);
TRUE_MAP_LIB_DECLARE_FUNCTION(tmZoomIn);
TRUE_MAP_LIB_DECLARE_FUNCTION(tmZoomOut);
TRUE_MAP_LIB_DECLARE_FUNCTION(tmIsMaxZoom);
TRUE_MAP_LIB_DECLARE_FUNCTION(tmIsMinZoom);
TRUE_MAP_LIB_DECLARE_FUNCTION(tmGetMaxZoomLevel);
TRUE_MAP_LIB_DECLARE_FUNCTION(tmGetMinZoomLevel);
TRUE_MAP_LIB_DECLARE_FUNCTION(tmGetMeterFromPixelWidth);
TRUE_MAP_LIB_DECLARE_FUNCTION(tmGetMeterFromPixelHeight);
TRUE_MAP_LIB_DECLARE_FUNCTION(tmGetScreenPointFromLocation);
TRUE_MAP_LIB_DECLARE_FUNCTION(tmGetLocationFromScreenPoint);
TRUE_MAP_LIB_DECLARE_FUNCTION(tmGetLocationFromScreenCenter);
TRUE_MAP_LIB_DECLARE_FUNCTION(tmGetLocationScreenRect);
TRUE_MAP_LIB_DECLARE_FUNCTION(tmGetMovedPoint);
TRUE_MAP_LIB_DECLARE_FUNCTION(tmInvalidate);
TRUE_MAP_LIB_DECLARE_FUNCTION(tmRegisterEventCallback);

#ifdef __cplusplus
namespace TRUEMapLib
{
	extern "C"
	{
#endif // __cplusplus

		// Private functions
		static TMVoid tmUninitAllFunctions();

		TMBoolean tmInitLibrary()
		{
			TMBoolean bSucceed;

			if(g_hDLL != NULL)
			{
				// If the module is already loaded, the return value is FALSE
				return FALSE;
			}

			g_hDLL = ::LoadLibrary(TRUE_MAP_LIB_DLL_FILE_NAME);

			if(g_hDLL == NULL)
			{
				return FALSE;
			}

			bSucceed = TRUE;

			bSucceed &= TRUE_MAP_LIB_LOAD_FUNCTION(tmCreate);
			bSucceed &= TRUE_MAP_LIB_LOAD_FUNCTION(tmDestroy);
			bSucceed &= TRUE_MAP_LIB_LOAD_FUNCTION(tmLoad);
			bSucceed &= TRUE_MAP_LIB_LOAD_FUNCTION(tmGetMapHWND);
			bSucceed &= TRUE_MAP_LIB_LOAD_FUNCTION(tmSetMapCenterLocationWithZoomLevel);
			bSucceed &= TRUE_MAP_LIB_LOAD_FUNCTION(tmSetMapCenterLocation);
			bSucceed &= TRUE_MAP_LIB_LOAD_FUNCTION(tmMoveCenterPointWithZoomLevel);
			bSucceed &= TRUE_MAP_LIB_LOAD_FUNCTION(tmMoveCenterPoint);
			bSucceed &= TRUE_MAP_LIB_LOAD_FUNCTION(tmSetZoomLevel);
			bSucceed &= TRUE_MAP_LIB_LOAD_FUNCTION(tmGetZoomLevel);
			bSucceed &= TRUE_MAP_LIB_LOAD_FUNCTION(tmZoomIn);
			bSucceed &= TRUE_MAP_LIB_LOAD_FUNCTION(tmZoomOut);
			bSucceed &= TRUE_MAP_LIB_LOAD_FUNCTION(tmIsMaxZoom);
			bSucceed &= TRUE_MAP_LIB_LOAD_FUNCTION(tmIsMinZoom);
			bSucceed &= TRUE_MAP_LIB_LOAD_FUNCTION(tmGetMaxZoomLevel);
			bSucceed &= TRUE_MAP_LIB_LOAD_FUNCTION(tmGetMinZoomLevel);
			bSucceed &= TRUE_MAP_LIB_LOAD_FUNCTION(tmGetMeterFromPixelWidth);
			bSucceed &= TRUE_MAP_LIB_LOAD_FUNCTION(tmGetMeterFromPixelHeight);
			bSucceed &= TRUE_MAP_LIB_LOAD_FUNCTION(tmGetScreenPointFromLocation);
			bSucceed &= TRUE_MAP_LIB_LOAD_FUNCTION(tmGetLocationFromScreenPoint);
			bSucceed &= TRUE_MAP_LIB_LOAD_FUNCTION(tmGetLocationFromScreenCenter);
			bSucceed &= TRUE_MAP_LIB_LOAD_FUNCTION(tmGetLocationScreenRect);
			bSucceed &= TRUE_MAP_LIB_LOAD_FUNCTION(tmGetMovedPoint);
			bSucceed &= TRUE_MAP_LIB_LOAD_FUNCTION(tmInvalidate);
			bSucceed &= TRUE_MAP_LIB_LOAD_FUNCTION(tmRegisterEventCallback);

			if(bSucceed == FALSE)
			{
				tmUninitAllFunctions();

				::FreeLibrary(g_hDLL);
				g_hDLL = NULL;
			}

			return bSucceed;
		}

		TMBoolean tmUninitLibrary()
		{
			if(g_hDLL == NULL)
			{
				// If the module is not loaded, the return value is FALSE
				return FALSE;
			}

			tmUninitAllFunctions();
			::FreeLibrary(g_hDLL);
			g_hDLL = NULL;

			return TRUE;
		}

		TMVoid tmUninitAllFunctions()
		{
			TRUE_MAP_LIB_SET_FUNCTION_TO_NULL(tmCreate);
			TRUE_MAP_LIB_SET_FUNCTION_TO_NULL(tmDestroy);
			TRUE_MAP_LIB_SET_FUNCTION_TO_NULL(tmLoad);
			TRUE_MAP_LIB_SET_FUNCTION_TO_NULL(tmGetMapHWND);
			TRUE_MAP_LIB_SET_FUNCTION_TO_NULL(tmSetMapCenterLocationWithZoomLevel);
			TRUE_MAP_LIB_SET_FUNCTION_TO_NULL(tmSetMapCenterLocation);
			TRUE_MAP_LIB_SET_FUNCTION_TO_NULL(tmMoveCenterPointWithZoomLevel);
			TRUE_MAP_LIB_SET_FUNCTION_TO_NULL(tmMoveCenterPoint);
			TRUE_MAP_LIB_SET_FUNCTION_TO_NULL(tmSetZoomLevel);
			TRUE_MAP_LIB_SET_FUNCTION_TO_NULL(tmGetZoomLevel);
			TRUE_MAP_LIB_SET_FUNCTION_TO_NULL(tmZoomIn);
			TRUE_MAP_LIB_SET_FUNCTION_TO_NULL(tmZoomOut);
			TRUE_MAP_LIB_SET_FUNCTION_TO_NULL(tmIsMaxZoom);
			TRUE_MAP_LIB_SET_FUNCTION_TO_NULL(tmIsMinZoom);
			TRUE_MAP_LIB_SET_FUNCTION_TO_NULL(tmGetMaxZoomLevel);
			TRUE_MAP_LIB_SET_FUNCTION_TO_NULL(tmGetMinZoomLevel);
			TRUE_MAP_LIB_SET_FUNCTION_TO_NULL(tmGetMeterFromPixelWidth);
			TRUE_MAP_LIB_SET_FUNCTION_TO_NULL(tmGetMeterFromPixelHeight);
			TRUE_MAP_LIB_SET_FUNCTION_TO_NULL(tmGetScreenPointFromLocation);
			TRUE_MAP_LIB_SET_FUNCTION_TO_NULL(tmGetLocationFromScreenPoint);
			TRUE_MAP_LIB_SET_FUNCTION_TO_NULL(tmGetLocationFromScreenCenter);
			TRUE_MAP_LIB_SET_FUNCTION_TO_NULL(tmGetLocationScreenRect);
			TRUE_MAP_LIB_SET_FUNCTION_TO_NULL(tmGetMovedPoint);
			TRUE_MAP_LIB_SET_FUNCTION_TO_NULL(tmInvalidate);
			TRUE_MAP_LIB_SET_FUNCTION_TO_NULL(tmRegisterEventCallback);
		}

		TMMapHandle					TM_API_CALLING_CONVENTION tmCreate(DWORD dwStyle, RECT rect, HWND hParentWnd, HINSTANCE hInstance)
		{
			if(g_tmCreate != NULL)
			{
				return ((TMMapHandle (TM_API_CALLING_CONVENTION *)(DWORD dwStyle, RECT rect, HWND hParentWnd, HINSTANCE hInstance))g_tmCreate)(dwStyle, rect, hParentWnd, hInstance);
			}

			return NULL;
		}

		TMBoolean					TM_API_CALLING_CONVENTION tmDestroy(TMMapHandle hMap)
		{
			if(g_tmDestroy != NULL)
			{
				return ((TMBoolean (TM_API_CALLING_CONVENTION *)(TMMapHandle hMap))g_tmDestroy)(hMap);
			}

			return FALSE;
		}

		TMBoolean					TM_API_CALLING_CONVENTION tmLoad(TMMapHandle hMap, TMMapType mapType, TMLocation center, TMDouble dZoomLevel)
		{
			if(g_tmLoad != NULL)
			{
				return ((TMBoolean (TM_API_CALLING_CONVENTION *)(TMMapHandle hMap, TMMapType mapType, TMLocation center, TMDouble dZoomLevel))g_tmLoad)(hMap, mapType, center, dZoomLevel);
			}

			return FALSE;
		}

		HWND						TM_API_CALLING_CONVENTION tmGetMapHWND(TMMapHandle hMap)
		{
			if(g_tmGetMapHWND != NULL)
			{
				return ((HWND (TM_API_CALLING_CONVENTION *)(TMMapHandle hMap))g_tmGetMapHWND)(hMap);
			}

			return NULL;
		}

		TMBoolean					TM_API_CALLING_CONVENTION tmSetMapCenterLocationWithZoomLevel(TMMapHandle hMap, TMLocation center, TMDouble dZoomLevel)
		{
			if(g_tmSetMapCenterLocationWithZoomLevel != NULL)
			{
				return ((TMBoolean (TM_API_CALLING_CONVENTION *)(TMMapHandle hMap, TMLocation center, TMDouble dZoomLevel))g_tmSetMapCenterLocationWithZoomLevel)(hMap, center, dZoomLevel);
			}

			return FALSE;
		}

		TMBoolean					TM_API_CALLING_CONVENTION tmSetMapCenterLocation(TMMapHandle hMap, TMLocation center)
		{
			if(g_tmSetMapCenterLocation != NULL)
			{
				return ((TMBoolean (TM_API_CALLING_CONVENTION *)(TMMapHandle hMap, TMLocation center))g_tmSetMapCenterLocation)(hMap, center);
			}

			return FALSE;
		}

		TMBoolean					TM_API_CALLING_CONVENTION tmMoveCenterPointWithZoomLevel(TMMapHandle hMap, TMPoint delta, TMDouble dZoomLevel)
		{
			if(g_tmMoveCenterPointWithZoomLevel != NULL)
			{
				return ((TMBoolean (TM_API_CALLING_CONVENTION *)(TMMapHandle hMap, TMPoint delta, TMDouble dZoomLevel))g_tmMoveCenterPointWithZoomLevel)(hMap, delta, dZoomLevel);
			}

			return FALSE;
		}

		TMBoolean					TM_API_CALLING_CONVENTION tmMoveCenterPoint(TMMapHandle hMap, TMPoint delta)
		{
			if(g_tmMoveCenterPoint != NULL)
			{
				return ((TMBoolean (TM_API_CALLING_CONVENTION *)(TMMapHandle hMap, TMPoint delta))g_tmMoveCenterPoint)(hMap, delta);
			}

			return FALSE;
		}

		TMBoolean					TM_API_CALLING_CONVENTION tmSetZoomLevel(TMMapHandle hMap, TMDouble dZoomLevel)
		{
			if(g_tmSetZoomLevel != NULL)
			{
				return ((TMBoolean (TM_API_CALLING_CONVENTION *)(TMMapHandle hMap, TMDouble dZoomLevel))g_tmSetZoomLevel)(hMap, dZoomLevel);
			}

			return FALSE;
		}

		TMDouble					TM_API_CALLING_CONVENTION tmGetZoomLevel(TMMapHandle hMap)
		{
			if(g_tmGetZoomLevel != NULL)
			{
				return ((TMDouble (TM_API_CALLING_CONVENTION *)(TMMapHandle hMap))g_tmGetZoomLevel)(hMap);
			}

			return 0.0;
		}

		TMBoolean					TM_API_CALLING_CONVENTION tmZoomIn(TMMapHandle hMap)
		{
			if(g_tmZoomIn != NULL)
			{
				return ((TMBoolean (TM_API_CALLING_CONVENTION *)(TMMapHandle hMap))g_tmZoomIn)(hMap);
			}

			return FALSE;
		}

		TMBoolean					TM_API_CALLING_CONVENTION tmZoomOut(TMMapHandle hMap)
		{
			if(g_tmZoomOut != NULL)
			{
				return ((TMBoolean (TM_API_CALLING_CONVENTION *)(TMMapHandle hMap))g_tmZoomOut)(hMap);
			}

			return FALSE;
		}

		TMBoolean					TM_API_CALLING_CONVENTION tmIsMaxZoom(TMMapHandle hMap)
		{
			if(g_tmIsMaxZoom != NULL)
			{
				return ((TMBoolean (TM_API_CALLING_CONVENTION *)(TMMapHandle hMap))g_tmIsMaxZoom)(hMap);
			}

			return FALSE;
		}

		TMBoolean					TM_API_CALLING_CONVENTION tmIsMinZoom(TMMapHandle hMap)
		{
			if(g_tmIsMinZoom != NULL)
			{
				return ((TMBoolean (TM_API_CALLING_CONVENTION *)(TMMapHandle hMap))g_tmIsMinZoom)(hMap);
			}

			return FALSE;
		}

		TMDouble					TM_API_CALLING_CONVENTION tmGetMaxZoomLevel(TMMapHandle hMap)
		{
			if(g_tmGetMaxZoomLevel != NULL)
			{
				return ((TMDouble (TM_API_CALLING_CONVENTION *)(TMMapHandle hMap))g_tmGetMaxZoomLevel)(hMap);
			}

			return 0.0;
		}

		TMDouble					TM_API_CALLING_CONVENTION tmGetMinZoomLevel(TMMapHandle hMap)
		{
			if(g_tmGetMinZoomLevel != NULL)
			{
				return ((TMDouble (TM_API_CALLING_CONVENTION *)(TMMapHandle hMap))g_tmGetMinZoomLevel)(hMap);
			}

			return 0.0;
		}

		TMDouble					TM_API_CALLING_CONVENTION tmGetMeterFromPixelWidth(TMMapHandle hMap, TMDouble dMapLevel, TMInteger nPixelWidth)
		{
			if(g_tmGetMeterFromPixelWidth != NULL)
			{
				return ((TMDouble (TM_API_CALLING_CONVENTION *)(TMMapHandle hMap, TMDouble dMapLevel, TMInteger nPixelWidth))g_tmGetMeterFromPixelWidth)(hMap, dMapLevel, nPixelWidth);
			}

			return 0.0;
		}

		TMDouble					TM_API_CALLING_CONVENTION tmGetMeterFromPixelHeight(TMMapHandle hMap, TMDouble dMapLevel, TMInteger nPixelHeight)
		{
			if(g_tmGetMeterFromPixelHeight != NULL)
			{
				return ((TMDouble (TM_API_CALLING_CONVENTION *)(TMMapHandle hMap, TMDouble dMapLevel, TMInteger nPixelHeight))g_tmGetMeterFromPixelHeight)(hMap, dMapLevel, nPixelHeight);
			}

			return 0.0;
		}

		TMPoint						TM_API_CALLING_CONVENTION tmGetScreenPointFromLocation(TMMapHandle hMap, TMLocation location)
		{
			if(g_tmGetScreenPointFromLocation != NULL)
			{
				return ((TMPoint (TM_API_CALLING_CONVENTION *)(TMMapHandle hMap, TMLocation location))g_tmGetScreenPointFromLocation)(hMap, location);
			}

			return TMPoint();
		}

		TMLocation					TM_API_CALLING_CONVENTION tmGetLocationFromScreenPoint(TMMapHandle hMap, TMPoint point)
		{
			if(g_tmGetLocationFromScreenPoint != NULL)
			{
				return ((TMLocation (TM_API_CALLING_CONVENTION *)(TMMapHandle hMap, TMPoint point))g_tmGetLocationFromScreenPoint)(hMap, point);
			}

			return TMLocation();
		}

		TMLocation					TM_API_CALLING_CONVENTION tmGetLocationFromScreenCenter(TMMapHandle hMap)
		{
			if(g_tmGetLocationFromScreenCenter != NULL)
			{
				return ((TMLocation (TM_API_CALLING_CONVENTION *)(TMMapHandle hMap))g_tmGetLocationFromScreenCenter)(hMap);
			}

			return TMLocation();
		}

		TMLocationRect				TM_API_CALLING_CONVENTION tmGetLocationScreenRect(TMMapHandle hMap)
		{
			if(g_tmGetLocationScreenRect != NULL)
			{
				return ((TMLocationRect (TM_API_CALLING_CONVENTION *)(TMMapHandle hMap))g_tmGetLocationScreenRect)(hMap);
			}

			return TMLocationRect();
		}

		TMPoint						TM_API_CALLING_CONVENTION tmGetMovedPoint(TMMapHandle hMap)
		{
			if(g_tmGetMovedPoint != NULL)
			{
				return ((TMPoint (TM_API_CALLING_CONVENTION *)(TMMapHandle hMap))g_tmGetMovedPoint)(hMap);
			}

			return TMPoint();
		}

		TMBoolean					TM_API_CALLING_CONVENTION tmInvalidate(TMMapHandle hMap)
		{
			if(g_tmInvalidate != NULL)
			{
				return ((TMBoolean (TM_API_CALLING_CONVENTION *)(TMMapHandle hMap))g_tmInvalidate)(hMap);
			}

			return FALSE;
		}

		TMBoolean					TM_API_CALLING_CONVENTION tmRegisterEventCallback(TMMapHandle hMap, PFN_TRUE_MAP_LIB_EVENT_CALLBACK pfnTarget, TMVoid *pUserParam)
		{
			if(g_tmRegisterEventCallback != NULL)
			{
				return ((TMBoolean (TM_API_CALLING_CONVENTION *)(TMMapHandle hMap, PFN_TRUE_MAP_LIB_EVENT_CALLBACK pfnTarget, TMVoid *pUserParam))g_tmRegisterEventCallback)(hMap, pfnTarget, pUserParam);
			}

			return FALSE;
		}
#ifdef __cplusplus
	} // extern "C"
} // namespace TRUEMapLib
#endif // __cplusplus